package dbu.dbase;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public abstract class DBaseStructure {

	protected byte readByte(InputStream stream) throws IOException {
		return (byte) stream.read();
	}

	protected short readShort(InputStream stream) throws IOException {
		byte[] buff = new byte[2];
		stream.read(buff);
		short result =  (short) ((buff[0] & 0xFF) + ((buff[1] & 0xFF) << 8));
		return result;
	}

	protected Date readYYMMDD(InputStream stream) throws IOException {
		byte[] buff = new byte[3];
		stream.read(buff);
		Date date = getDate(buff);
		return date;
	}

	protected byte[] getYYMMDD(Date date) {
		byte[] buff = new byte[3];
		Calendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		buff[0] = (byte) (calendar.get(Calendar.YEAR)  - 1900);
		buff[1] = (byte) calendar.get(Calendar.MONTH);
		buff[2] = (byte) calendar.get(Calendar.DATE);
		return buff;
	}

	private Date getDate(byte[] yymmdd) {
		Calendar calendar = new GregorianCalendar();
		calendar.set(Calendar.YEAR, (yymmdd[0] & 0xFF) + 1900);
		calendar.set(Calendar.MONTH, yymmdd[1] & 0xFF);
		calendar.set(Calendar.DATE, yymmdd[2] & 0xFF);
		return calendar.getTime();
	}

	protected int readInt(InputStream stream) throws IOException {
		byte[] buff = new byte[4];
		stream.read(buff);
		int result =  (int) ((buff[0] & 0xFF) + ((buff[1] & 0xFF) << 8) + ((buff[2] & 0xFF) << 16) + ((buff[3] & 0xFF) << 24));
		return result;
	}

	/**
	 * d	ieee	dbase
	 * 0.0	00  	34 01
	 * 1.0	3f f0	35 09 10
	 * 2.0	40  	35 09 20 
	 * 3.0			35 09 30 
	 * 4.0			35 09 40 
	 * 5.0			35 09 50 
	 * 6.0			35 09 60 
	 * 7.0			35 09 70 
	 * 8.0			35 09 80 
	 * 9.0			35 09 90 
	 * 10.0			36 09 10 
	 * 11.0			36 09 11 
	 * 12.0			36 09 12 
	 * 13.0			36 09 13 
	 * 14.0			36 09 14 
	 */
	protected double readDouble(InputStream stream) throws IOException {
		byte[] buff = new byte[8];
		stream.read(buff);
		long j = ((buff[7] & 0xFFL) << 0) +
				 ((buff[6] & 0xFFL) << 8) +
				 ((buff[5] & 0xFFL) << 16) +
				 ((buff[4] & 0xFFL) << 24) +
				 ((buff[3] & 0xFFL) << 32) +
				 ((buff[2] & 0xFFL) << 40) +
				 ((buff[1] & 0xFFL) << 48) +
				 (((long) buff[0]) << 56);
		double result = Double.longBitsToDouble(j);
		return result;
	}

	protected void writeDouble(OutputStream stream, double val) throws IOException {
		byte[] buff = new byte[8];
		long j = Double.doubleToLongBits(val);
		buff[7] = (byte) (j >>> 0);
		buff[6] = (byte) (j >>> 8);
		buff[5] = (byte) (j >>> 16);
		buff[4] = (byte) (j >>> 24);
		buff[3] = (byte) (j >>> 32);
		buff[2] = (byte) (j >>> 40);
		buff[1] = (byte) (j >>> 48);
		buff[0] = (byte) (j >>> 56);
		stream.write(buff);
	}

	protected String readString(InputStream stream, int size) throws IOException {
		byte[] buff = new byte[size];
		stream.read(buff);
		String result = new String(buff);
		return result;
	}

	protected void writeString(OutputStream stream, String s, int len) throws IOException {
		byte[] result = new byte[len];
		for (int i = 0; i < s.length() && i < len; i++) {
			result[i] = (byte) s.charAt(i);
		}
		stream.write(result);
	}

	protected byte[] readBuff(InputStream stream, int size) throws IOException {
		byte[] buff = new byte[size];
		stream.read(buff);
		return buff;
	}

	abstract protected int read(InputStream in) throws IOException;
}
